package com.lanchetech.admin.service.impl;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.lanchetech.admin.service.ProductService;
import com.lanchetech.bean.dto.SnapshotDTO;
import com.lanchetech.bean.request.*;
import com.lanchetech.bean.response.*;
import com.lanchetech.bean.util.PageHelpUtil;
import com.lanchetech.bean.vo.*;
import com.lanchetech.common.enums.*;
import com.lanchetech.common.exception.ResultCodeException;
import com.lanchetech.dao.*;
import com.lanchetech.entity.*;
import com.lanchetech.service.DaoService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.lanchetech.common.constants.JypConstant.MAX_AMOUNT;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    SpuMapper spuMapper;

    @Autowired
    SpecMapper specMapper;

    @Autowired
    CategorySpecMapper categorySpecMapper;

    @Autowired
    UnitMapper unitMapper;

    @Autowired
    FreightMapper freightMapper;

    @Autowired
    SkuMapper skuMapper;

    @Autowired
    SpuAttributeMapper spuAttributeMapper;

    @Autowired
    CategoryMapper categoryMapper;

    @Autowired
    FreightListMapper freightListMapper;

    @Autowired
    SnapshotMapper snapshotMapper;

    @Autowired
    BrandMapper brandMapper;

    @Autowired
    DaoService daoService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    CommentStatisticsMapper commentStatisticsMapper;

    @Autowired
    SpuCommissionMapper spuCommissionMapper;

    @Autowired
    SkuCommissionMapper skuCommissionMapper;

    @Autowired
    SpuCourierAmountMapper spuCourierAmountMapper;

    @Autowired
    ShopMapper shopMapper;

    @Autowired
    AppointmentSettingMapper appointmentSettingMapper;

    @Autowired
    ZoneMapper zoneMapper;

    @Autowired
    ZoneSpuMapper zoneSpuMapper;

    @Autowired
    SelectionApplyMapper selectionApplyMapper;

    @Autowired
    SelectionMapper selectionMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    ShopCategoryMapper shopCategoryMapper;

    /**
     * 模糊删除redis，支持通配符
     *
     * @param key
     */
    private void deleteRedisByKey(String key) {
        Set<String> keys = redisTemplate.keys(key);
        if (!CollectionUtils.isEmpty(keys)) {
            redisTemplate.delete(keys);
        }
    }

    public boolean computedIsUseCache(SpuReq req) {
        // 只缓存首页，并且没有搜索其他内容
        return req.getPageNo() == 1 && req.getAuditStatus() == null && req.getCategoryId() == null && req.getHidden() == null && req.getIsVirtual() == null && req.getName() == null && req.getBrandId() == null;
    }

    @Override
    public ResultData<BasePageResp<SpuResp>> getSpuPage(SpuReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<SpuResp> list = spuMapper.findAllAdminPage(req);
        if (CollectionUtils.isEmpty(list)) {
            return PageHelpUtil.buildPage(list, page);
        }

        Map<Long, Category> categoryMap = daoService.getCategoryMap(list.stream().map(Spu::getCategoryId).collect(Collectors.toList()));
        Map<Long, Brand> brandMap = daoService.getBrandMap(list.stream().map(Spu::getBrandId).collect(Collectors.toList()));
        Map<Long, Freight> freightMap = daoService.getFreightMap(list.stream().map(Spu::getFreightId).collect(Collectors.toList()));
        Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(Spu::getTenantId).collect(Collectors.toList()));


        //总库存统计
        List<Sku> allSku = skuMapper.findAllBySpuIds(list.stream().map(SpuResp::getId).collect(Collectors.toList()));
        Map<Long, Integer> spuStockMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(allSku)) {
            allSku.stream().forEach(item -> {
                Integer stock = spuStockMap.get(item.getSpuId());
                Integer skuStock = item.getStock() == null ? 0 : item.getStock();
                if (stock == null) {
                    spuStockMap.put(item.getSpuId(), skuStock);
                } else {
                    spuStockMap.put(item.getSpuId(), skuStock + stock);
                }
            });
        }

        list.stream().forEach((item) -> {
            item.setCategoryTitle(categoryMap.get(item.getCategoryId()).getTitle());
            item.setBrandName(brandMap.containsKey(item.getBrandId()) ? brandMap.get(item.getBrandId()).getName() : null);
            item.setFreightName(freightMap.get(item.getFreightId()).getName());
            item.setShopAvatar(shopMap.get(item.getTenantId()).getAvatar());
            item.setShopNickname(shopMap.get(item.getTenantId()).getShopName());
            item.setTotalStock(spuStockMap.get(item.getId()));
        });

        ResultData<BasePageResp<SpuResp>> result = PageHelpUtil.buildPage(list, page);
        return result;
    }

    @Override
    public ResultData<BasePageResp<SpuResp>> getProductPage(SpuReq req) {
        boolean isUseCache = computedIsUseCache(req);
        ValueOperations<String, ResultData<BasePageResp<SpuResp>>> operations = redisTemplate.opsForValue();
        String key = "AdminProductPage:" + DigestUtils.md5DigestAsHex((JSON.toJSONString(req)).getBytes());
        if (isUseCache) {
            ResultData<BasePageResp<SpuResp>> result = operations.get(key);
            if (result != null) {
                return result;
            }
        }
        ResultData<BasePageResp<SpuResp>> result = getSpuPage(req);
        if (CollectionUtils.isEmpty(result.getValue().getData())) {
            return result;
        }
        // 获取skuList
        Map<Long, List<Sku>> skuListMap = daoService.getSkuListMap(result.getValue().getData().stream().map(SpuResp::getId).collect(Collectors.toList()));
        result.getValue().getData().stream().forEach(item -> item.setSkuList(skuListMap.get(item.getId())));
        if (isUseCache) {
            operations.set(key, result, 10, TimeUnit.MINUTES);
        }
        return result;
    }

    /**
     * 创建商品SPU级快照
     * 0.0.1: 初始版本
     *
     * @param spu
     * @param spuAttributes
     */
    private void createSnapshot(Spu spu, List<SpuAttribute> spuAttributes) {
        SnapshotDTO snapshotDTO = new SnapshotDTO(spu, spuAttributes);
        Snapshot snapshot = Snapshot.builder().spuId(spu.getId()).version("0.0.1").content(JSON.toJSONString(snapshotDTO)).createdAt(new Date()).tenantId(spu.getTenantId()).build();
        snapshotMapper.insert(snapshot);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResp editSpuAndSku(SpuEditVO spuEditVO) {
        Spu spu = spuEditVO.getSpu();
        List<Sku> skuList = spuEditVO.getSkuList();
        List<SpuAttribute> spuAttributeList = spuEditVO.getSpuAttributeList();
        Category category = categoryMapper.selectByPrimaryKey(spu.getCategoryId());

        if (spu.getShopId() == null) {
            return new BaseResp(ResultCode.FAIL);
        }

        Shop shop = shopMapper.selectByPrimaryKey(spu.getShopId());
        spu.setLatitude(shop.getLatitude());
        spu.setLongitude(shop.getLongitude());
        spu.setIndustryFirstId(shop.getIndustryFirstId());
        spu.setIndustrySecondId(shop.getIndustrySecondId());
        spu.setAuditStatus(SpuAuditStatusEnum.PASS.getAuditStatus());

        if (!CollectionUtils.isEmpty(skuList)) {
            // 批量设置供货价
            for (Sku item : skuList) {
                BigDecimal costPrice = item.getPrice().multiply(BigDecimal.ONE.subtract(shop.getServiceRate())).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                if (item.getCostPrice() == null || item.getCostPrice().compareTo(costPrice) > 0) {
                    item.setCostPrice(costPrice);
                }
                // 如果没设置，则设置默认值
                if (item.getChangePrice() == null || item.getChangePrice().compareTo(BigDecimal.ZERO) <= 0) {
                    item.setChangePrice(costPrice);
                }
                item.setType(spu.getType());

            }

        }

        // 如果主播佣金比例大于30%，则不允许
        if (spu.getAnchorProportion().compareTo(BigDecimal.valueOf(0.3)) > 0) {
            return new BaseResp(ResultCode.SPU_COMMISSION_ERROR);
        }

        if (spuEditVO.getSpu().getId() == null) {
            // 新建
            spu.setDeleted((byte) 0);
            spu.setSales(0);
            spu.setFiveStar(0);
            spu.setCreatedAt(new Date());
            spu.setUpdatedAt(new Date());
            spu.setTenantId(spu.getShopId());
            spu.setRid(category.getRid() != null ? category.getRid() : category.getId());
            if (spu.getLimitCount() == null) {
                spu.setLimitCount(0L);
            }
            if (spu.getFlashHidden() == null) {
                spu.setFlashHidden(ToggleEnum.ON.getStatus());
            }

            spuMapper.insert(spu);

            for (Sku sku : skuList) {
                sku.setSpuId(spu.getId());
                sku.setSales(0);
                sku.setDeleted((byte) 0);
                sku.setCreatedAt(new Date());
                sku.setUpdatedAt(new Date());
                sku.setTenantId(spu.getShopId());
                if (sku.getPartnerPrice() == null) {
                    sku.setPartnerPrice(sku.getPrice());
                }
                if (sku.getVipPrice() == null) {
                    sku.setVipPrice(sku.getPrice());
                }
            }
            skuMapper.batchInsert(skuList);

            if (spuAttributeList != null && spuAttributeList.size() > 0) {
                spuAttributeMapper.batchInsert(spuAttributeList, spu.getId());
            }

            // 初始化spu评价统计
            commentStatisticsMapper.insert(new CommentStatistics(null, spu.getId(), 0, 0, 0, 0, 0, 0, 0, 0));
        } else {
            // 编辑
            spu.setUpdatedAt(new Date());
            spu.setTenantId(spu.getShopId());
            spuMapper.updateByPrimaryKeySelective(spu);

            if (spuEditVO.getIsSkuChange()) {
                List<Sku> skuResult = skuMapper.findAllBySpuId(spu.getId());
                Map<String, Sku> skuMap = new HashMap<>();
                skuResult.stream().forEach(item -> skuMap.put(item.getSpecValues(), item));

                // 拆分出删除、插入、更新
                List<Sku> skuDelete = new ArrayList<>();
                List<Sku> skuInsert = new ArrayList<>();
                List<Sku> skuUpdate = new ArrayList<>();

                Map<String, Sku> newSkuMap = new HashMap<>();
                skuList.stream().forEach(item -> {
                    item.setTenantId(spu.getTenantId());
                    if (skuMap.containsKey(item.getSpecValues())) {
                        item.setUpdatedAt(new Date());
                        skuUpdate.add(item);
                    } else {
                        item.setSpuId(spu.getId());
                        item.setSales(0);
                        item.setDeleted((byte) 0);
                        item.setCreatedAt(new Date());
                        item.setUpdatedAt(new Date());
                        skuInsert.add(item);
                    }
                    newSkuMap.put(item.getSpecValues(), item);
                });
                skuResult.forEach(item -> {
                    item.setTenantId(spu.getTenantId());
                    if (!newSkuMap.containsKey(item.getSpecValues())) {
                        skuDelete.add(item);
                    }
                });
                // 先删除，再插入，再更新
                if (!CollectionUtils.isEmpty(skuDelete)) {
                    skuMapper.updateDeletedByIdIn(DeletedEnum.DELETED.getStatus(), skuDelete.stream().map(Sku::getId).collect(Collectors.toList()));
                }
                if (!CollectionUtils.isEmpty(skuInsert)) {
                    skuMapper.batchInsert(skuInsert);
                }
                if (!CollectionUtils.isEmpty(skuUpdate)) {
                    skuMapper.updateBatchSelective(skuUpdate);
                }
            } else {
                // 如果sku只是修改了价格数量，则只更新
                for (Sku sku : skuList) {
                    sku.setTenantId(spu.getTenantId());
                    sku.setUpdatedAt(new Date());
                }
                skuMapper.updateBatchSelective(skuList);
            }

            spuAttributeMapper.deleteBySpuId(spu.getId());
            if (spuAttributeList != null && spuAttributeList.size() > 0) {
                spuAttributeMapper.batchInsert(spuAttributeList, spu.getId());
            }
        }

        // 创建快照
        createSnapshot(spu, spuAttributeList);

        // 删除管理后台缓存
        deleteRedisByKey("AdminProductPage*");
        deleteRedisByKey("HomeInfoResp");
        deleteRedisByKey("AdminSpuPage*");
        deleteRedisByKey("SpuPage*");
        deleteRedisByKey("ProductDetail:" + spu.getId() + ":*");
        deleteRedisByKey("SkuList:" + spu.getId() + ":*");
        deleteRedisByKey("LikeSpu:" + spu.getCategoryId());
        deleteRedisByKey("MerchantProductPage:" + spu.getTenantId() + ":*");
        deleteRedisByKey("MerchantSpuPage:" + spu.getTenantId() + ":*");

        //重新统计并保存数据
        Spu existSpu = spuMapper.selectByPrimaryKey(spu.getId());
        saveSpuStatistics(spuEditVO.getSpu(), existSpu.getCategoryId());

        return new BaseResp();
    }

    private void saveSpuStatistics(Spu spu, Long categoryId) {
        List<Long> categroyList = new ArrayList<>();
        categroyList.add(categoryId);
        saveSpuStatistics(spu, categroyList);
    }

    @Override
    public BaseResp editSpuSort(Spu req) {
        spuMapper.updateSortsById(req.getSorts(), req.getId());
        deleteRedisByKey("AdminProductPage*");
        deleteRedisByKey("AdminSpuPage*");
        deleteRedisByKey("SpuPage*");
        return new BaseResp();
    }

    @Override
    public ResultData<SpuEditVO> getSpuEditDetail(Long id) {
        SpuEditVO spuEditVO = new SpuEditVO();
        Spu spu = spuMapper.selectByPrimaryKey(id);
        Category category = categoryMapper.selectByPrimaryKey(spu.getCategoryId());
        List<Category> categoryList = new ArrayList<>();
        if (category.getLevel().equals(2)) {
            Category parentCategory = categoryMapper.selectByPrimaryKey(category.getPid());
            Category rootCategory = categoryMapper.selectByPrimaryKey(category.getRid());
            categoryList.add(rootCategory);
            categoryList.add(parentCategory);
            categoryList.add(category);
        } else if (category.getLevel().equals(1)) {
            Category parentCategory = categoryMapper.selectByPrimaryKey(category.getPid());
            categoryList.add(parentCategory);
            categoryList.add(category);
        } else {
            categoryList.add(category);
        }

        spuEditVO.setCategoryList(categoryList);
        spuEditVO.setSpu(spu);
        spuEditVO.setSkuList(skuMapper.findAllBySpuId(id));
        spuEditVO.setSpuAttributeList(spuAttributeMapper.findAllBySpuId(id));

        if (spu.getShopId() != null && spu.getShopId() > 0) {
            Shop shop = shopMapper.selectByPrimaryKey(spu.getShopId());
            spuEditVO.setShopName(shop.getShopName());
            spuEditVO.setServiceRate(shop.getServiceRate());
        }
        return new ResultData<>(spuEditVO);
    }

    @Override
    public ResultData<BasePageResp<Spec>> getSpecPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Spec> list = specMapper.findAllPage(req);
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<List<Spec>> getSpecList() {
        return new ResultData<>(specMapper.findAll());
    }

    @Override
    public BaseResp editSpec(Spec spec) {
        if (spec.getId() == null) {
            // 添加
            spec.setCreatedAt(new Date());
            spec.setUpdatedAt(new Date());
            specMapper.insert(spec);
        } else {
            // 编辑
            spec.setUpdatedAt(new Date());
            specMapper.updateByPrimaryKeySelective(spec);
        }
        return new BaseResp();
    }

    @Override
    public BaseResp deleteSpec(Long id) {
        specMapper.deleteByPrimaryKey(id);
        // 删除关联类目
        categorySpecMapper.deleteBySpecId(id);
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<Unit>> getUnitPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Unit> list = unitMapper.findAllPage(req);
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public BaseResp editUnit(Unit unit) {
        if (unit.getId() == null) {
            unitMapper.insert(unit);
        } else {
            unitMapper.updateByPrimaryKey(unit);
        }
        return new BaseResp();
    }

    @Override
    public BaseResp deleteUnit(Long id) {
        unitMapper.deleteByPrimaryKey(id);
        return new BaseResp();
    }

    @Override
    public ResultData<List<Unit>> getUnitList() {
        return new ResultData<>(unitMapper.findAll());
    }

    @Override
    public ResultData<BasePageResp<FreightTenantVO>> getFreightPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Freight> list = freightMapper.findAllPage(req);
        Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(Freight::getTenantId).collect(Collectors.toList()));
        List<FreightTenantVO> voList = new ArrayList<>();
        list.stream().forEach(item -> {
            FreightTenantVO vo = new FreightTenantVO();
            BeanUtils.copyProperties(item, vo);
            vo.setShopName(shopMap.get(item.getTenantId()).getShopName());
            vo.setShopAvatar(shopMap.get(item.getTenantId()).getAvatar());
            voList.add(vo);
        });
        return PageHelpUtil.buildPage(voList, page);
    }

    @Override
    public BaseResp editFreight(FreightVO freightVO) {
        Freight freight = freightVO.getFreight();
        if (freight.getFirstWeight().compareTo(MAX_AMOUNT) > 0 || freight.getAdditionalWeight().compareTo(MAX_AMOUNT) > 0) {
            return new BaseResp(ResultCode.OUT_OF_AMOUNT_RANGE);
        }
        List<FreightList> freightLists = freightVO.getFreightLists();
        Boolean overMax = false;
        for (int i = 0; i < freightLists.size(); i++) {
            if (freightLists.get(i).getFirstWeight().compareTo(MAX_AMOUNT) > 0 || freightLists.get(i).getAdditionalWeight().compareTo(MAX_AMOUNT) > 0) {
                overMax = true;
                break;
            }
        }
        if (overMax) {
            return new BaseResp(ResultCode.OUT_OF_AMOUNT_RANGE);
        }
        if (freight.getId() == null) {
            freight.setDeleted((byte) 0);
            freight.setCreatedAt(new Date());
            freight.setUpdatedAt(new Date());
            freightMapper.insert(freight);
        } else {
            freight.setUpdatedAt(new Date());
            // 不允许修改商户
            freight.setTenantId(null);
            freightMapper.updateByPrimaryKeySelective(freight);
            freightListMapper.deleteByFreightId(freight.getId());
        }

        for (FreightList item : freightLists) {
            item.setFreightId(freight.getId());
        }
        if (!CollectionUtils.isEmpty(freightLists)) {
            freightListMapper.batchInsert(freightLists);
        }
        return new BaseResp();
    }

    @Override
    public ResultData<FreightVO> getFreightDetail(Long id) {
        FreightVO freightVO = new FreightVO();
        freightVO.setFreight(freightMapper.selectByPrimaryKey(id));
        freightVO.setFreightLists(freightListMapper.findAllByFreightId(id));
        freightVO.setShopName(shopMapper.selectByPrimaryKey(freightVO.getFreight().getTenantId()).getShopName());
        return new ResultData<>(freightVO);
    }

    @Override
    public BaseResp deleteFreight(Long id) {
        Freight freight = freightMapper.selectByPrimaryKey(id);
        Long count = freightMapper.countByTenantIdAndDeleted(freight.getTenantId(), DeletedEnum.DEFAULT.getStatus());
        if (count == null && count.equals(0L)) {
            return new BaseResp(ResultCode.FREIGHT_CAN_NOT_BE_EMPTY);
        }
        freightMapper.updateDeletedById((byte) 1, id);
        return new BaseResp();
    }

    @Override
    public ResultData<List<Freight>> getFreightList(Long tenantId) {
        return new ResultData<>(freightMapper.findAllByTenantId(tenantId));
    }

    @Override
    public BaseResp deleteProduct(Long id) {
        Spu spu = spuMapper.selectByPrimaryKey(id);

        //更新商品统计数据
        saveSpuStatistics(null, spu.getCategoryId());

        //如果是预约商品删除设置
        if (ShopSpuTypeEnum.APPOINTMENT.getType().equals(spu.getShopSpuType())) {
            appointmentSettingMapper.updateDeletedBySpuId(DeletedEnum.DELETED.getStatus(), spu.getId());
        }

        spuMapper.updateDeletedById(DeletedEnum.DELETED.getStatus(), id);
        skuMapper.updateDeletedBySpuId(DeletedEnum.DELETED.getStatus(), id);
        // 删除管理后台缓存
        deleteRedisByKey("AdminProductPage*");
        deleteRedisByKey("AdminSpuPage*");
        deleteRedisByKey("SpuPage*");
        deleteRedisByKey("ProductDetail:" + spu.getId() + ":*");
        deleteRedisByKey("SkuList:" + spu.getId() + ":*");
        deleteRedisByKey("LikeSpu:" + spu.getCategoryId());
        return new BaseResp();
    }


    @Override
    public ResultData<BasePageResp<SkuWithCommissionVO>> getSkuAndSkuCommissionPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Sku> skuList = skuMapper.findAllBySpuId(req.getSpuId());
        Spu spu = spuMapper.selectByPrimaryKey(req.getSpuId());
        List<SkuCommission> skuCommissionList = skuCommissionMapper.findAllBySkuIds(skuList.stream().map(Sku::getId).collect(Collectors.toList()));
        Map<Long, SkuCommission> skuCommissionMap = new HashMap<>();
        skuCommissionList.stream().forEach(item -> skuCommissionMap.put(item.getSkuId(), item));
        List<SkuWithCommissionVO> result = new ArrayList<>();
        skuList.stream().forEach(item -> {
            SkuWithCommissionVO vo = new SkuWithCommissionVO();
            BeanUtils.copyProperties(item, vo);
            vo.setSkuCommission(skuCommissionMap.get(item.getId()));
            vo.setName(spu.getName());
            result.add(vo);
        });
        return PageHelpUtil.buildPage(result, page);
    }

    @Override
    public BaseResp editSkuCommission(SkuCommission req) {
        // 2、佣金配置总额必须等于商品的销售价
        Sku sku = skuMapper.selectByPrimaryKey(req.getSkuId());
        if (sku.getPrice().compareTo(req.getPlatformCommission().add(req.getV1Commission()).add(req.getV2Commission()).add(req.getV3Commission()).add(req.getV4Commission()).add(req.getV5Commission()).add(req.getV2CommissionPlus()).add(req.getShareCommission())) != 0) {
            return new BaseResp(ResultCode.SKU_COMMISSION_SUM_ERROR);
        }

        SkuCommission result = skuCommissionMapper.findOneBySkuId(req.getSkuId());

        if (result == null) {
            // 1、佣金配置不能重复
            req.setCreatedAt(new Date());
            req.setUpdatedAt(new Date());
            skuCommissionMapper.insert(req);
        } else {
            req.setId(result.getId());
            req.setSpuId(null);
            req.setSkuId(null);
            req.setUpdatedAt(new Date());
            skuCommissionMapper.updateByPrimaryKeySelective(req);
        }
        return new BaseResp();
    }

    @Override
    public BaseResp deleteSkuCommission(Long id) {
        skuCommissionMapper.deleteByPrimaryKey(id);
        return new BaseResp();
    }

    @Override
    public BaseResp editSpuCourierAmount(SpuCourierAmount req) {
        SpuCourierAmount old = spuCourierAmountMapper.findOneBySpuId(req.getSpuId());
        if (old == null) {
            req.setCreatedAt(new Date());
            spuCourierAmountMapper.insert(req);
        } else {
            req.setId(old.getId());
            spuCourierAmountMapper.updateByPrimaryKeySelective(req);
        }
        return new BaseResp();
    }

    @Override
    public ResultData<SpuCourierAmount> getSpuCourierAmount(Long spuId) {
        return new ResultData<>(spuCourierAmountMapper.findOneBySpuId(spuId));
    }

    @Override
    public BaseResp editZone(ZoneReq req) {
        if (req.getId() == null) {
            Zone zone = Zone.builder().title(req.getTitle()).mainImage(req.getMainImage()).backgroundColor(req.getBackgroundColor()).deleted(DeletedEnum.DEFAULT.getStatus()).createdAt(new Date()).updatedAt(new Date()).tenantId(0L).build();
            if (req.getNewZone() == null) {
                zone.setNewZone(ToggleEnum.OFF.getStatus());
            }
            zoneMapper.insert(zone);

            if (!CollectionUtils.isEmpty(req.getList())) {
                req.getList().stream().forEach(item -> {
                    item.setZoneId(zone.getId());
                    item.setNewZone(zone.getNewZone());
                    item.setCreatedAt(new Date());
                    item.setUpdatedAt(new Date());
                });
                zoneSpuMapper.batchInsert(req.getList());
            }
        } else {
            Zone zone = zoneMapper.selectByPrimaryKey(req.getId());
            zoneMapper.updateByPrimaryKeySelective(req);
            zoneSpuMapper.deleteByZoneId(req.getId());
            if (!CollectionUtils.isEmpty(req.getList())) {
                req.getList().stream().forEach(item -> {
                    item.setZoneId(req.getId());
                    item.setNewZone(req.getNewZone() == null ? zone.getNewZone() : req.getNewZone());
                    item.setCreatedAt(new Date());
                    item.setUpdatedAt(new Date());
                });
                zoneSpuMapper.batchInsert(req.getList());
            }
        }
        redisTemplate.delete("HomeInfoResp");
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<Zone>> getZonePage(ZonePageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Zone> list = zoneMapper.findAllPage(req);
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<ZoneVO> getZoneSpuDetail(Long zoneId) {
        ZoneVO vo = new ZoneVO();
        Zone zone = zoneMapper.selectByPrimaryKey(zoneId);
        BeanUtils.copyProperties(zone, vo);
        List<ZoneSpuVO> zoneSpuVOList = zoneSpuMapper.findAllByZoneId(zoneId);
        if (!org.apache.commons.collections.CollectionUtils.isEmpty(zoneSpuVOList)) {
            Map<Long, Spu> spuMap = daoService.getSpuMap(zoneSpuVOList.stream().map(ZoneSpuVO::getSpuId).collect(Collectors.toList()));
            zoneSpuVOList.stream().forEach(item -> {
                item.setName(spuMap.get(item.getSpuId()).getName());
                item.setImage(spuMap.get(item.getSpuId()).getMainImage());
                item.setPrice(spuMap.get(item.getSpuId()).getMinPrice());
                item.setFeature(spuMap.get(item.getSpuId()).getFeature());
                item.setSales(spuMap.get(item.getSpuId()).getSales());
            });
        }
        vo.setZoneSpuVOList(zoneSpuVOList);
        return new ResultData<>(vo);
    }

    @Override
    public BaseResp deleteZone(Long zoneId) {
        zoneMapper.updateDeletedById(DeletedEnum.DELETED.getStatus(), zoneId);
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<SelectionApplyVO>> getSelectionApplyPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<SelectionApplyVO> list = selectionApplyMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, User> userMap = daoService.getUserMap(list.stream().map(SelectionApplyVO::getUserId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setUserNickname(userMap.get(item.getUserId()).getUsername());
                item.setAvatar(userMap.get(item.getUserId()).getAvatar());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public BaseResp auditSelectionApply(SelectionApply req) {
        SelectionApply selectionApply = selectionApplyMapper.selectByPrimaryKey(req.getId());
        selectionApply.setUpdatedAt(new Date());
        selectionApply.setAuditStatus(req.getAuditStatus());
        selectionApply.setRemark(req.getRemark());
        selectionApplyMapper.updateByPrimaryKey(selectionApply);
        return new BaseResp();
    }

    @Override
    public ResultData<SelectionApplyVO> getSelectionApplyDetail(Long id) {
        SelectionApply selectionApply = selectionApplyMapper.selectByPrimaryKey(id);
        SelectionApplyVO vo = new SelectionApplyVO();
        BeanUtils.copyProperties(selectionApply, vo);
        User user = userMapper.selectByPrimaryKey(selectionApply.getUserId());
        vo.setUserNickname(user.getNickname());
        vo.setAvatar(user.getAvatar());
        vo.setSelectionList(selectionMapper.findAllBySelectionApplyId(id));
        return new ResultData<>(vo);
    }

    @Override
    public BaseResp auditSelection(Selection req) {
        Selection selection = selectionMapper.selectByPrimaryKey(req.getId());
        selection.setRemark(req.getRemark());
        selection.setStatus(req.getStatus());
        selectionMapper.updateByPrimaryKeySelective(selection);
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<Selection>> getSelectionPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Selection> list = selectionMapper.findAllPage(req);
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public void exportSelectionExcel(PageReq req, HttpServletResponse response) throws IOException {
        String fileName = new String(("选品列表导出数据.xlsx").getBytes(), "UTF-8");
        List<Selection> list = selectionMapper.findAllPage(req);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        EasyExcel.write(response.getOutputStream(), Selection.class).sheet("选品列表导出数据").doWrite(list);
    }

    @Override
    public BaseResp batchOfflineProduct(BatchOfflineReq req) {
        List<Long> spuIds = req.getSpuIds();
        if (!CollectionUtils.isEmpty(spuIds)) {
            spuMapper.batchOffline(spuIds, req.getHidden());
            skuMapper.batchOffline(spuIds, req.getHidden());

            //下架商品更新统计数据
            List<Spu> spuList = spuMapper.findAllByIds(spuIds);
            saveSpuStatistics(null, spuList.stream().map(Spu::getCategoryId).collect(Collectors.toList()));

            // 删除管理后台缓存
            deleteRedisByKey("AdminProductPage*");
            deleteRedisByKey("AdminSpuPage*");
            deleteRedisByKey("SpuPage*");
        }

        return new BaseResp();
    }

    private void saveSpuStatistics(Spu spu, List<Long> categoryIds) {
        //添加删除或修改了商品名称就更新统计数据
        ValueOperations<String, List<TagSpuStatisticsVO>> operations = redisTemplate.opsForValue();
        if (spu == null || spu.getName() != null) {
            //标题总字数
            List<StatisticsCountVO> totalWordCounts = spuMapper.getTotalWordCountByCategoryIds(categoryIds);
            Map<Long, Long> totalWordCountMap = new HashMap<>();
            if (!org.apache.commons.collections.CollectionUtils.isEmpty(totalWordCounts)) {
                totalWordCounts.stream().forEach(item -> {
                    totalWordCountMap.put(item.getId(), item.getCount());
                });
            }

            //博文总数
            List<StatisticsCountVO> itemCount = spuMapper.getItemCountByCategoryIds(categoryIds);
            Map<Long, Long> itemCountMap = new HashMap<>();
            if (!org.apache.commons.collections.CollectionUtils.isEmpty(itemCount)) {
                itemCount.stream().forEach(item -> {
                    itemCountMap.put(item.getId(), item.getCount());
                });
            }

            //计算统计数量
            List<TagSpuStatisticsVO> voList = new ArrayList<>();
            totalWordCounts.stream().forEach(item -> {
                TagSpuStatisticsVO vo = new TagSpuStatisticsVO();
                vo.setType(UserTagTypeEnum.SPU.getType());
                vo.setRelateId(item.getId());
                vo.setItemCount(itemCountMap.get(item.getId()));
                vo.setUpdateAt(new Date());
                vo.setTotalWordCount(totalWordCountMap.get(item.getId()));
                voList.add(vo);
            });

            if (operations.get("tfidf" + UserTagTypeEnum.SPU.getType()) != null) {
                //更新下架的类目统计
                List<TagSpuStatisticsVO> statisticsVO = operations.get("tfidf" + UserTagTypeEnum.SPU.getType());
                statisticsVO = statisticsVO.stream().filter(Objects::nonNull).collect(Collectors.toList());
                List<Long> relateIds = statisticsVO.stream().map(TagSpuStatisticsVO::getRelateId).collect(Collectors.toList());
                List<TagSpuStatisticsVO> addStatistics = new ArrayList<>();

                Map<Long, TagSpuStatisticsVO> statisticsVOMap = new HashMap<>();
                statisticsVO.stream().forEach(item -> {
                    statisticsVOMap.put(item.getRelateId(), item);
                });

                voList.stream().forEach(item -> {
                    if (relateIds.contains(item.getRelateId())) {
                        BeanUtils.copyProperties(item, statisticsVOMap.get(item.getRelateId()));
                    } else {
                        addStatistics.add(item);
                    }
                });
                if (!CollectionUtils.isEmpty(addStatistics)) {
                    statisticsVO.addAll(addStatistics);
                }
                operations.set("tfidf" + UserTagTypeEnum.SPU.getType(), statisticsVO);
            }
        }
    }

    @Override
    public BaseResp resetSorts(Long startNum, Long endNum) {
        spuMapper.resetSorts(startNum, endNum);
        return new BaseResp();
    }

    @Override
    public BaseResp auditProduct(Long spuId, Byte type, String message) {
        Spu spu = spuMapper.selectByPrimaryKey(spuId);
        if (SpuAuditStatusEnum.WAIT_AUDIT.getAuditStatus().equals(spu.getAuditStatus())) {
            if (ToggleEnum.ON.getStatus().equals(type)) {
                spu.setHidden(SpuHiddenEnum.VISIBLE.getType());
                spu.setAuditStatus(SpuAuditStatusEnum.PASS.getAuditStatus());

                List<Sku> skuList = skuMapper.findAllBySpuId(spuId);
                List<Long> changeSku = new ArrayList<>();
                if (!CollectionUtils.isEmpty(skuList)) {
                    skuList.stream().forEach(item -> {
                        if (item.getChangePrice().compareTo(BigDecimal.ZERO) > 0) {
                            changeSku.add(item.getId());
                        }
                    });
                }
                if (!CollectionUtils.isEmpty(changeSku)) {
                    skuMapper.updateCostPriceByChangePrice(changeSku);
                }
                spuMapper.updateByPrimaryKeySelective(spu);
            } else {
                spuMapper.updateAuditStatusAndAuditMessageById(SpuAuditStatusEnum.REFUSE.getAuditStatus(), message, spuId);
            }
        }
        // 删除管理后台缓存
        deleteRedisByKey("AdminProductPage*");
        deleteRedisByKey("AdminSpuPage*");
        deleteRedisByKey("SpuPage*");
        deleteRedisByKey("MerchantSpuPage:" + spu.getTenantId() + ":*");
        deleteRedisByKey("MerchantProductPage:" + spu.getTenantId() + ":*");
        return new BaseResp();
    }

    @Override
    public ResultData<List<SpuVO>> getTopSpu() {
        return new ResultData<>(spuMapper.findTopSpu());
    }

    @Override
    public ResultData<BasePageResp<BossRankingVo>> getBossRanking(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<BossRankingVo> vo = spuMapper.getBossRanking(req);
        return PageHelpUtil.buildPage(vo, page);
    }

    @Override
    public BaseResp updateSpu(SpuEditVO spuEditVO) throws ResultCodeException {
        if (spuEditVO.getSpu() == null) {
            throw new ResultCodeException(ResultCode.PARAMETER_NULL);
        }
        Spu spu = spuEditVO.getSpu();
        spuMapper.updateByPrimaryKeySelective(spu);
        return new BaseResp();
    }

    @Override
    public BaseResp preferredImage(Long spuId, boolean main) {
        spuMapper.preferredImage(spuId, main);
        return new BaseResp();
    }
}